package com.foreveross.project.projectonline.jfinal.tx;

import java.lang.reflect.Method;
import java.sql.Connection;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.NestedTransactionHelpException;

/**
 * @title: TODO
 * @className: TxServiceInterceptor
 * @company: FOREVEROSS
 * @author: <a href="mailto:jiangwei@foreveross.com">vakin jiang</a>
 * @createDate: 2014年8月8日
 * @version: 1.0
 */
public class TxServiceInterceptor implements MethodInterceptor {

	private final Logger logger = LoggerFactory.getLogger(TxServiceInterceptor.class);

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object result = null;
		Object target = invocation.getThis();
		Method targetMethod = invocation.getMethod();
		System.out.println("===========Enter==============" + targetMethod.getName());
		Class<?>[] targetMethodParamTypes = targetMethod.getParameterTypes();
		Method method = target.getClass().getMethod(targetMethod.getName(), targetMethodParamTypes);
		if (method.isAnnotationPresent(TxService.class)) { // 如果存在事务的话，需要使用到jfinal提供的事务支持。
			logger.debug("当前正在对" + target.getClass().getName() + "的" + targetMethod.getName() + "方法进行事务拦截");
			try {
				result = doInvoke(invocation);
			} catch (Throwable e) {
				throw e;
			} finally {
				AfterTxThreadLocal.me().doUpdateElasticSearch();
			}
			return result;
		}
		try {
			result = invocation.proceed();
		} catch (Throwable e) {
			throw e;
		} finally {
			AfterTxThreadLocal.me().doUpdateElasticSearch();
		}
		return result; // 如果没有事务的话，直接调用方法
	}

	public Object doInvoke(MethodInvocation invocation) {
		Config config = DbKit.getConfig();

		Connection conn = config.getThreadLocalConnection();
		if (conn != null) { // Nested transaction support
			int transactionLevel = config.getTransactionLevel();
			try {
				if (conn.getTransactionIsolation() < transactionLevel) {
					conn.setTransactionIsolation(transactionLevel);
				}
				return invocation.proceed();
			} catch (Throwable e) {
				throw new ActiveRecordException(e);
			}
		}

		Boolean autoCommit = null;
		try {
			conn = config.getConnection();
			autoCommit = conn.getAutoCommit();
			config.setThreadLocalConnection(conn);
			conn.setTransactionIsolation(config.getTransactionLevel()); // conn.setTransactionIsolation(transactionLevel);
			conn.setAutoCommit(false);
			Object object = invocation.proceed();
			conn.commit();
			return object;
		} catch (NestedTransactionHelpException e) {
			if (conn != null)
				try {
					conn.rollback();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
		} catch (Throwable e) {
			if (conn != null)
				try {
					conn.rollback();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			throw new ActiveRecordException(e);
		} finally {
			try {
				System.out.println("===========Exit==============" + invocation.getMethod().getName());
				if (conn != null) {
					if (autoCommit != null) {
						conn.setAutoCommit(autoCommit);
					}
					conn.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				config.removeThreadLocalConnection(); // prevent memory leak
			}
		}
		return null;
	}
}
